import InstrumentationPackage.*;
import EventPackage.*;

class FireMonitor extends EventProcessor implements Runnable {

    private static final long DELAY_BETWEEN_EVENTS_MILLIS = 500L;
    private MessageWindow messageWindow; // This is the message window
    private boolean fireDetected;
    private boolean sprinklerCountdownInitiated;
    private long sprinklerCountdownInitiatedTimeMillis;
    private static final long SPRINKLER_COUNTDOWN_LIMIT_SECONDS = 15L;
    private boolean disableFireAlarmCountdownInitiated;
    private long disableFireAlarmCountdownInitiatedTimeMillis;
    private static final long DISABLE_FIRE_ALARM_COUNTDOWN_LIMIT_SECONDS = 10L;

    public FireMonitor() {
        this(null);
    }

    public FireMonitor(String eventManagerIpAddress) {
        super(eventManagerIpAddress, DELAY_BETWEEN_EVENTS_MILLIS);
    }

    @Override
    protected EventType[] getEventTypesToRegister() {
        return new EventType[]{
            EventType.CONSOLE_MESSAGE,
            EventType.FIRE_EVENT_ON,
            EventType.FIRE_EVENT_OFF
        };
    }   

    private static final MessageWindow createMessageWindow(String windowName, float posX, float posY) {
        return new MessageWindow(windowName, posX, posY);
    }

    @Override
    public void run() {
        try {
            processEvents();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onRegistered() {
        messageWindow = createMessageWindow("Fire Monitor Console", 0.05f, 0.5f);
        messageWindow.WriteMessage("Registered fire monitor");
    }

    @Override
    protected void onUnregistered() {
        messageWindow.WriteMessage("Unregistered fire monitor");
    }

    @Override
    protected void onProcessing() {
        if (sprinklerCountdownInitiated) {
            if ((System.currentTimeMillis() - sprinklerCountdownInitiatedTimeMillis) >= (SPRINKLER_COUNTDOWN_LIMIT_SECONDS * 1000L)) {
                // Engage the sprinkler system, time has expired
                enableSprinklers();
            }
        } else if (disableFireAlarmCountdownInitiated) {
            if ((System.currentTimeMillis() - disableFireAlarmCountdownInitiatedTimeMillis) >= (DISABLE_FIRE_ALARM_COUNTDOWN_LIMIT_SECONDS * 1000L)) {
                // Sufficient time without a fire event has passed since
                // the last time a fire event was detected, disable the alarm
                disableFireAlarm();
            }
        }
    }

    @Override
    protected void onEvent(Event event) {
        if (EventType.CONSOLE_MESSAGE.isEvent(event.GetEventId(), event.GetMessage())) {
            writeMessage(event.GetMessage());
        } else if (EventType.FIRE_EVENT_ON.isEvent(event.GetEventId(), event.GetMessage())) {
            // A fire event is detected
            enableFireAlarm();
            if (!fireDetected) {
                // A previous fire event was not detected
                sprinklerCountdownInitiated = true;
                sprinklerCountdownInitiatedTimeMillis = System.currentTimeMillis();
                fireDetected = true;
                writeMessage("WARNING: A fire event was detected.  The sprinkler system will engage in " +
                        SPRINKLER_COUNTDOWN_LIMIT_SECONDS + " seconds unless it is disabled from the console.");
            }
        } else if (EventType.FIRE_EVENT_OFF.isEvent(event.GetEventId(), event.GetMessage())) {
            // A fire event is NOT detected.  
            if (fireDetected) {
                //A previous fire event had been detected though the fire
                //event is no longer detected.  Set fireDetected to false but do
                // not automatically disable the fire alarm -- disabling the fire
                // alarm must be done by the system after sufficient time has passed
                // without receiving another fire event.
                disableFireAlarmCountdownInitiated = true;
                disableFireAlarmCountdownInitiatedTimeMillis = System.currentTimeMillis();
                fireDetected = false;
                writeMessage("NOTICE: The fire event has passed.  The fire alarm will silence in " +
                        DISABLE_FIRE_ALARM_COUNTDOWN_LIMIT_SECONDS + " seconds unless a subsequent fire event is detected.");
            }
        }
    }

    private void writeMessage(String message) {
        if (messageWindow != null) {
            messageWindow.WriteMessage(message);
        }
    }

    public void enableSprinklers() {
        writeMessage("*** COMMAND:  Enable Sprinkler ***");
        sendEvent(new Event(EventType.SPRINKLER_ON.getEventId(), EventType.SPRINKLER_ON.getEventMessage()));
        sprinklerCountdownInitiated = false;
    }

    public void disableSprinklers() {
        writeMessage("*** COMMAND:  Disable Sprinkler ***");
        sendEvent(new Event(EventType.SPRINKLER_OFF.getEventId(), EventType.SPRINKLER_OFF.getEventMessage()));
        sprinklerCountdownInitiated = false;
    }

    public void enableFireAlarm() {
        writeMessage("*** COMMAND:  Enable Fire Alarm ***");
        sendEvent(new Event(EventType.FIRE_ALARM_ON.getEventId(), EventType.FIRE_ALARM_ON.getEventMessage()));
        disableFireAlarmCountdownInitiated = false;
    }

    public void disableFireAlarm() {
        writeMessage("*** COMMAND:  Disable Fire Alarm ***");
        sendEvent(new Event(EventType.FIRE_ALARM_OFF.getEventId(), EventType.FIRE_ALARM_OFF.getEventMessage()));
        disableFireAlarmCountdownInitiated = false;
    }

    public void halt() {
        writeMessage("*** COMMAND:  Shutdown System ***");
        sendEvent(new Event(EventType.TERMINATE.getEventId(), "shutdown system"));
    }

    public void confirmAndEngageSprinklers() {
        writeMessage("*** COMMAND:  Confirm and Engage Sprinkler System ***");
        sendEvent(new Event(EventType.SPRINKLER_ON.getEventId(), EventType.SPRINKLER_ON.getEventMessage()));
        sprinklerCountdownInitiated = false;
    }
}
